﻿#region copyright
//<copyright>
// Copyright(C) 2012 TrackerRealm Corporation
// This file is part of the open source project - Jazz. http://jazz.codeplex.com
// 
// Jazz is open software: you can redistribute it and/or modify it 
// under the terms of the GNU Affero General Public License (AGPL) as published by 
// the Free Software Foundation, version 3 of the License.
// 
// Jazz is distributed in the hope that it will be useful, 
// but WITHOUT ANY WARRANTY; without even the implied warranty 
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
//  See the GNU Affero General Public License (AGPL) for more details.
// 
// You should have received a copy of the GNU General Public 
// License along with Jazz.  If not, see <http://www.gnu.org/licenses/>.
//
// REMOVAL OF THIS NOTICE IS VIOLATION OF THE COPYRIGHT. 
//</copyright>
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Reflection;

namespace TrackerRealm.Jazz.Client
{
    /// <summary>
    /// 
    /// </summary>
    public class RulesCollection : IEnumerable<jRuleInfo>, ICollection<jRuleInfo>
    {
       
        /// <summary>
        /// 
        /// </summary>
        /// <param name="jclass"></param>
        /// <returns></returns>
        public static RulesCollection Create(jClass jclass)
        {
            return new RulesCollection(jclass);
        }
        jRuleInfo[] ruleArray;
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="jclass"></param>
        private RulesCollection(jClass jclass)
        {
            List<jRuleInfo> mList = new List<jRuleInfo>(8);

            Type t = jclass.JazzObjectType;
            while (t.Name != "jObject")
            {
                //MethodInfo[] ms = t.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic);
                foreach (MethodInfo m in t.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic))
                {
                    object[] stateMethods = m.GetCustomAttributes(typeof(RuleAttribute), true);
                    if (stateMethods.Length > 1)
                        throw new Exception(String.Format("Only a single rule Attribute is allow for a method. See method '{0}'-{1}", m.Name, t.FullName));
                    if (stateMethods.Length == 1)
                    {
                        mList.Add(new jRuleInfo((MethodInfo)m, null));
                        continue;
                    }
                }
                t = t.BaseType;
            }
            this.ruleArray = mList.ToArray();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="jazzObject"></param>
        internal void ExecuteRules(jObject jazzObject)
        {
            foreach (jRuleInfo rule in this)
            {
                rule.Execute(jazzObject);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public jRuleInfo Find(string name)
        {
            jRuleInfo rule = this.ruleArray.FirstOrDefault(s => s.Name == name);
            if (rule == null) return jRuleInfo.EmptyRule;
            return rule;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="name"></param>
        /// <param name="rule"></param>
        /// <returns></returns>
        public bool TryFind(string name, out jRuleInfo rule)
        {
            rule = this.ruleArray.FirstOrDefault(s => s.Name == name);
            if (rule == null) return false;
            return true;
        }
        /// <summary>
        /// 
        /// </summary>
        public jState StartState
        {
            get;
            private set;
        }
        #region IEnumerable<jState> Members
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public IEnumerator<jRuleInfo> GetEnumerator()
        {
            return ((IEnumerable<jRuleInfo>)this.ruleArray).GetEnumerator();
        }

        #endregion

        #region IEnumerable Members
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }

        #endregion

        #region ICollection<jRole> Members
        /// <summary>
        /// 
        /// </summary>
        /// <param name="item"></param>
        public void Add(jRuleInfo item)
        {
            throw new InvalidOperationException();
        }
        /// <summary>
        /// 
        /// </summary>
        public void Clear()
        {
            throw new InvalidOperationException();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public bool Contains(jRuleInfo item)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="array"></param>
        /// <param name="arrayIndex"></param>
        public void CopyTo(jRuleInfo[] array, int arrayIndex)
        {
            this.ruleArray.CopyTo(array, arrayIndex);
        }
        /// <summary>
        /// 
        /// </summary>
        public int Count
        {
            get { return this.ruleArray.Length; }
        }
        /// <summary>
        /// 
        /// </summary>
        public bool IsReadOnly
        {
            get { return true; }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public bool Remove(jRuleInfo item)
        {
            throw new InvalidOperationException();
        }

        #endregion
    }
}
